#include "Session.h"
#include "Server.h"
#include <iostream>

#include "LogicSystem.h"

Session::Session(io_context &ioc, Server *server)
    : _socket(ioc), _server(server), _head_data(0) {
    _uuid = boost::uuids::to_string(boost::uuids::random_generator()());
}

Session::~Session() {
    clog << "会话断开，id = " << _uuid << endl;
}

tcp::socket &Session::GetSocket() {
    return _socket;
}

void Session::Start() {
    //先读取头部，为2字节id和2字节消息长度
    async_read(_socket, buffer(_head_data, 4),
               [this](const boost::system::error_code &ec, const std::size_t bytes_transferred) {
                   HandleReadHead(ec, bytes_transferred, shared_from_this());
               });
}

void Session::HandleReadHead(const boost::system::error_code &ec, const size_t bytes_transferred,
                             const shared_ptr<Session> &session) {
    if (!ec) {
        if (bytes_transferred < 4) {
            cerr << "读取头部小于4字节！" << endl;
        }

        //先读取前2字节消息ID
        unsigned short data_id = 0;
        memcpy(&data_id, _head_data, 2);
        data_id = boost::asio::detail::socket_ops::network_to_host_short(data_id);
        clog << "电文ID为 = " << data_id << endl;

        //再读取3-4字节消息长度
        unsigned short data_len = 0;
        memcpy(&data_len, _head_data + 2, 2);
        data_len = boost::asio::detail::socket_ops::network_to_host_short(data_len);
        clog << "电文长度为 = " << data_len << endl;

        //头部长度非法
        if (data_len > 2048) {
            std::cout << "头部长度非法 = " << data_len << endl;
            _server->ClearSession(_uuid);
            return;
        }
        _recv_msg_node = make_shared<RecvNode>(data_len, data_id);

        async_read(_socket, buffer(_recv_msg_node->_data, data_len),
                   [this, session](const boost::system::error_code &err, const size_t byte_transferred) {
                       HandleReadBody(err, byte_transferred, session);
                   });
    }
    else {
        _server->ClearSession(_uuid);
    }
}

void Session::HandleReadBody(const boost::system::error_code &ec, const size_t bytes_transferred,
                             const shared_ptr<Session> &session) {
    if (!ec) {
        clog << "信息长度 = " << bytes_transferred << endl;
        clog << "接收信息 = " << _recv_msg_node->_data << endl;
        //加入逻辑处理队列
        LogicSystem::GetInstance().PostMsgToQueue(make_shared<LogicNode>(session, _recv_msg_node));

        _recv_msg_node->Clear();
        memset(_head_data, 0, 4);

        async_read(_socket, buffer(_head_data, 4),
                   [this, session](const boost::system::error_code &err, const size_t byte_transferred) {
                       HandleReadHead(err, byte_transferred, session);
                   });
    }
    else {
        _server->ClearSession(_uuid);
    }
}

void Session::Close() {
    _socket.close();
}

string Session::GetUuid() {
    return _uuid;
}

//发送函数
void Session::Send(const string &msg, short msg_id) {
    lock_guard<mutex> lg(_send_lock);
    const auto send_queue_size = _send_queue.size();
    if (send_queue_size > 1000) {
        cerr << "session: " << _uuid << " 发送队列超长，长度 = " << send_queue_size << endl;
    }

    _send_queue.push(make_shared<SendNode>(msg.c_str(), msg.length(), msg_id));
    //如果之前发送队列中还有数据，那么让队列继续发送，这里不调用发送
    if (send_queue_size > 0)
        return;

    const auto send_msg_node = _send_queue.front();

    async_write(_socket, buffer(send_msg_node->_data, send_msg_node->_total_len),
                [this](const boost::system::error_code &err, size_t) {
                    HandleWrite(err, shared_from_this());
                });
}

//发送回调函数
void Session::HandleWrite(const boost::system::error_code &ec, const shared_ptr<Session> &session) {
    try {
        if (!ec) {
            lock_guard<mutex> lg(_send_lock);

            _send_queue.pop();
            if (!_send_queue.empty()) {
                const auto send_msg_node = _send_queue.front();

                async_write(_socket, buffer(send_msg_node->_data, send_msg_node->_total_len),
                            [this,session](const boost::system::error_code &err, size_t) {
                                HandleWrite(err, session);
                            });
            }
        }
        else {
            cerr << "发送失败: " << ec.message() << endl;
        }
    }
    catch (exception &e) {
        cerr << "异常，code = " << e.what() << endl;
    }
}

//逻辑处理节点
LogicNode::LogicNode(const shared_ptr<Session> &session, const shared_ptr<RecvNode> &recv_node)
    : _session(session), _recv_node(recv_node) {
}
